﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

namespace BToolkit
{
    public class Broadcaster : MonoBehaviour
    {
        private static Broadcaster _instance;
        public static Broadcaster Instance
        {
            get
            {
                if (!_instance)
                {
                    _instance = GameObject.FindObjectOfType<Broadcaster>();
                    if (!_instance)
                    {
                        GameObject go = new GameObject("Broadcaster");
                        DontDestroyOnLoad(go);
                        _instance = go.AddComponent<Broadcaster>();
                    }
                }
                return _instance;
            }
        }

        public event Action<ProtoBase> onReceive;

        private UdpClient client;
        private int port;
        private bool isThreadRun;

        private void Awake()
        {
            isThreadRun = true;
        }

        public void Init(int port)
        {
            if (client == null)
            {
                this.port = port;
                client = new UdpClient();
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                client.Client.Bind(new IPEndPoint(IPAddress.Any, port));
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0);
                MainThreadHelper.Init();
                new Thread(() =>
                {
                    while (isThreadRun)
                    {
                        if (client.Available > 0)
                        {
                            byte[] buffer = client.Receive(ref ipEndPoint);
                            MainThreadHelper.Run(() =>
                            {
                                onReceive?.Invoke(LitJson.JsonMapper.ToObject<ProtoBase>(Encoding.UTF8.GetString(buffer)));
                            });
                        }
                    }
                }).Start();
            }
        }

        /// <summary>
        /// targetIP为null则全局域网广播
        /// </summary>
        public void Send(ProtoBase protoBase, string targetIP = null)
        {
            if (client != null && protoBase != null)
            {
                try
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(LitJson.JsonMapper.ToJson(protoBase));
                    int limit = client.Client.SendBufferSize - 50;
                    if (bytes.Length > limit)
                    {
                        NetworkHelper.LogError($"数据大小{bytes.Length}超过了缓冲池{limit}限制");
                    }
                    if (string.IsNullOrEmpty(targetIP))
                    {
                        client.Send(bytes, bytes.Length, new IPEndPoint(IPAddress.Broadcast, port));
                    }
                    else
                    {
                        client.Send(bytes, bytes.Length, new IPEndPoint(IPAddress.Parse(targetIP), port));
                    }
                }
                catch (Exception ex)
                {
                    NetworkHelper.LogError(ex);
                }
            }
        }

        private void OnDestroy()
        {
            isThreadRun = false;
            if (client != null)
            {
                client.Close();
                client = null;
            }
        }
    }
}
